package view.layers;

import java.io.IOException;
import javax.microedition.lcdui.Graphics;
import model.Transportation;
import model.TransportationFactory;
import model.structs.Point;


/**
 * Represents the layer that the user has control over as far as movements.
 *
 * @author rhaq
 * @version 1.00 2009-05-06 Initial submission.
 */
public class UserLayer extends Layer
{
	/** Generates transportation objects as needed. */
	protected static TransportationFactory transFactory;

	/** A reference to the terrain that will need to be updated in case we reach critical points of the screen. */
	protected Layer terrain;

	/** The transportation object that the user is manipulating. */
	protected Transportation transportation;


	/**
	 * Creates an instance of this class with the specified dimensions and the specified terrain
	 * to update in case critical areas of the screen are accessed.
	 * @param width The width of this layer.
	 * @param height The height of this layer.
	 * @param terrain Reference to the terrain that will need updating in case the edges of the screen are accessed.
	 * @throws IOException If the graphics for this layer cannot be loaded.
	 */
	public UserLayer(int width, int height, Layer terrain) throws IOException
	{
		super(width, height);
		current.setY(19);

		this.terrain = terrain;
		transFactory = TransportationFactory.getInstance();
		this.transportation = transFactory.createHondaCivic();

		this.minimum = new Point();
		this.maximum = new Point(width, height);
	}


	/**
	 * Gets the absolute x-coordinate of this layer.
	 * @return The absolute value of the x-coordinate of this layer.
	 */
	protected int getTerrainX()
	{
		return Math.abs( terrain.current.getX() );
	}


	/**
	 * Gets the absolute y-coordinate of this layer.
	 * @return The absolute value of the y-coordinate of this layer.
	 */
	protected int getTerrainY()
	{
		return Math.abs( terrain.current.getY() );
	}


	/**
	 * Retrieves the user's transportation object that is stored in this layer.
	 * @return The transportation object that is stored in this layer that the user is manipulating.
	 */
	public Transportation getTransportation()
	{
		return transportation;
	}


	/* (non-Javadoc)
	 * @see view.layers.Layer#isBottomEdged()
	 */
	public boolean isBottomEdged()
	{
		return current.getY() >= maximum.getY();
	}


	/* (non-Javadoc)
	 * @see view.layers.Layer#isLeftEdged()
	 */
	public boolean isLeftEdged()
	{
		return current.getX() <= minimum.getX();
	}


	/* (non-Javadoc)
	 * @see view.layers.Layer#isRightEdged()
	 */
	public boolean isRightEdged()
	{
		return current.getX() >= maximum.getX();
	}


	/* (non-Javadoc)
	 * @see view.layers.Layer#isTopEdged()
	 */
	public boolean isTopEdged()
	{
		return current.getY() <= minimum.getY();
	}


	/* (non-Javadoc)
	 * @see view.layers.Layer#moveDown()
	 */
	public void moveDown()
	{
		current.incrementY( transportation.getSpeed() );

		while ( isBottomEdged() )
		{
			if ( terrain.isBottomEdged() ) // we're at the corner, no more moving
			{
				current.setY( maximum.getY() );
				break;
			}

			else // top edged, shift necessary
			{
				int orig = getTerrainY();
				terrain.moveUp();

				if ( terrain.isBottomEdged() )
				{
					int changed = getTerrainY();
					current.decrementY( changed-orig );
				}

				else
					current.resetY();
			}
		}
	}


	/* (non-Javadoc)
	 * @see view.layers.Layer#moveLeft()
	 */
	public void moveLeft()
	{
		current.decrementX( transportation.getSpeed() );

		while ( isLeftEdged() )
		{
			if ( terrain.isLeftEdged() ) // we're at the corner, no more moving
			{
				current.setX( minimum.getX() );
				break;
			}

			else // right edged, shift necessary
			{
				int orig = getTerrainX();
				terrain.moveRight();

				if ( terrain.isLeftEdged() )
				{
					int changed = getTerrainX();
					current.incrementX(changed-orig);
				}

				else
					current.setX( maximum.getX()-1 );
			}
		}
	}


	/* (non-Javadoc)
	 * @see view.layers.Layer#moveRight()
	 */
	public void moveRight()
	{
		current.incrementX( transportation.getSpeed() );

		while ( isRightEdged() )
		{
			if ( terrain.isRightEdged() ) // we're at the corner, no more moving
			{
				current.setX( maximum.getX() );
				break;
			}

			else // right edged, shift necessary
			{
				int orig = getTerrainX();
				terrain.moveLeft();

				if ( terrain.isRightEdged() )
				{
					int changed = getTerrainX();
					current.decrementX(changed-orig);
				}

				else
					current.resetX();
			}
		}
	}


	/* (non-Javadoc)
	 * @see view.layers.Layer#moveUp()
	 */
	public void moveUp()
	{
		current.decrementY( transportation.getSpeed() );

		while ( isTopEdged() )
		{
			if ( terrain.isTopEdged() ) // we're at the corner, no more moving
			{
				current.setY( minimum.getY() );
				break;
			}
						
			else // right edged, shift necessary
			{
				int orig = getTerrainY();
				terrain.moveDown();

				if ( terrain.isTopEdged() )
				{
					int changed = getTerrainY();
					current.incrementY(changed-orig);
				}

				else
					current.setY( maximum.getY()-1 );
			}
		}
	}


	/* (non-Javadoc)
	 * @see model.Layer#paint(javax.microedition.lcdui.Graphics)
	 */
	public void paint(Graphics g)
	{
		g.drawImage( transportation.getImage(), current.getX(), current.getY(), RELATIVE_POSITION);
	}


	/**
	 * Sets the transportation to the specified object.
	 * @param transportation The transportation to use instead.
	 */
	public void setTransportation(Transportation transportation)
	{
		this.transportation = transportation;
	}
}